#pragma once

//#include "util.h"
#include <vector>
#include <map>
#include <fstream>

using namespace std;

///////////////////////////////////////////////////////////////////////////////////
// This class loads .obj file into 3D models
// obj file defines vertex, texcoord, normal, material and texture files if used
///////////////////////////////////////////////////////////////////////////////////
class COBJLoader
{
    public:
	// Vertex format
	struct Vertex
	{
		D3DXVECTOR3 pos;    // position
		D3DXVECTOR3 norm;   //normal
		D3DXVECTOR2 tex;    //texture coordinate
	};

	// Used for a hashtable vertex cache when creating the mesh from a .obj file
	struct CacheEntry
	{
		UINT index;
		CacheEntry* pNext;
	};

    struct Material
    {
        WCHAR   strName[FILENAME_MAX];

        D3DXVECTOR3 vAmbient;
        D3DXVECTOR3 vDiffuse;
        D3DXVECTOR3 vSpecular;

        int nShininess;
        float fAlpha;

        bool bSpecular;

        WCHAR   strTexture[FILENAME_MAX];
        Material()
        {
            strName[0] = 0;
            strTexture[0] = 0;

            this->vAmbient = D3DXVECTOR3( 172/255.0f, 120/255.0f, 83/255.0f )*0.1;
            this->vDiffuse = D3DXVECTOR3( 172/255.0f, 120/255.0f, 83/255.0f )*0.3;
            this->vSpecular = D3DXVECTOR3( 0.02f, 0.02f, 0.02f );

            nShininess = 1;
            fAlpha = 1.0;

            bSpecular = false;
        }
    };


    struct Subset
    {
        int startIndex;
        int triangleCount;
        int materialID;
    };

private:
    HRESULT LoadMaterialsFromMTL( const WCHAR* strFileName );
    UINT AddVertex( UINT hash, Vertex* pVertex );


public:
	void GenerateNormal();
	void UpdateBoundingBox();

	COBJLoader(void);
	~COBJLoader(void);

    HRESULT LoadModelFromOBJ( const WCHAR* strFilename );
	void BuildMesh();

	void ScaleRotateTranslate(D3DXVECTOR3 scale, D3DXVECTOR3 rotation, D3DXVECTOR3 translation);
	void Clear();

    //UINT  GetNumMaterials() const				        { return m_Materials.size(); }
    //Material const* GetMaterial( UINT id ) const	    { return &m_Materials[id]; }
    WCHAR const* GetMediaDirectory() const				{ return m_strMediaDir;	}
    D3DXVECTOR3 GetBBMax() const                        { return m_bbMax; }
    D3DXVECTOR3 GetBBMin() const                        { return m_bbMin; }
    std::vector<Subset> const& GetSubsets() const       { return m_Subsets; }
    std::vector<Material> const& GetMaterials()	const   { return m_Materials; }
    std::vector<Vertex>	const& GetVertexBuffer() const  { return m_VertexBuffer; }
    std::vector<UINT> const& GetIndexBuffer() const     { return m_IndexBuffer; }

private:
	std::vector<Subset>				m_Subsets;			// all the sub meshes, each with different material property
    std::vector<Material>			m_Materials;
	std::vector<UINT>				m_IndexBuffer;
    std::vector<Vertex>		        m_VertexBuffer;
	std::vector<UINT>				m_AttributeBuffer;

	std::map<UINT, std::vector<UINT>> m_VertexCache;

	bool	m_bHasNormal;
	UINT	m_NumSubMeshes;
    WCHAR   m_strMediaDir[ FILENAME_MAX ];               // Directory where the mesh was found

	// Bounding box for the mesh
    D3DXVECTOR3     m_bbMax;
    D3DXVECTOR3     m_bbMin;
};
